package com.kehutong.house.admin;

import com.kehutong.common.DoveClient;
import com.kehutong.common.ExcelUtil;
import com.kehutong.common.permission.DataPermissionQuery;
import com.kehutong.common.permission.PermissionNameDto;
import com.kehutong.common.urlconfig.FileUrlConfig;
import com.kehutong.common.util.Token;
import com.kehutong.house.entity.Community;
import com.kehutong.house.entity.Parking;
import com.kehutong.house.entity.ParkingClassify;
import com.kehutong.house.service.HouseService;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.coraframework.authz.HasPermission;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.mvc.MvcAction;
import org.coraframework.mvc.http.Bean;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;
import org.coraframework.orm.jdbc.execute.entity.FindArray;
import org.coraframework.orm.jdbc.execute.entity.FindOne;
import org.coraframework.orm.jdbc.execute.entity.FindPage;
import org.coraframework.util.Objects;

import java.io.File;
import java.io.InputStream;
import java.util.*;

/**
 * 商铺分类
 */
@MvcAction
@ReqMapping("/admin/basic/parking/classify")
public class ParkingClassifyController {
	
	@Inject
	private JdbcSession jdbcSession;
	@Inject
	private DoveClient doveClient;
	@Inject
	private FileUrlConfig fileUrlConfig;
	@Inject
	private HouseService houseService;

	public final static String[] EXCEL_IMPORT_HEADER = {"项目/小区","分类名称"};

	static final Logger logger = LoggerFactory.getLogger(ParkingClassifyController.class);

	@HasPermission("basic:parking:classify:view")
	@ReqMapping("/listAll")
	public Object listAll(JSONObject jsonObject) throws Exception {
		FindArray<ParkingClassify> find = jdbcSession.findArray(ParkingClassify.class)
				.eq(jsonObject,"communityNo")
				.like(jsonObject, "communityName")
				.eq("deleted", false);

		PermissionNameDto dto = getParkingClassifyPermissionNameDto();

		houseService.setDataSql(find, dto, jsonObject, null);

		return find.exe(false);
	}

    @HasPermission("basic:parking:classify:view")
    @ReqMapping("/list")
    public Object list(JSONObject jsonObject) throws Exception {
    	FindPage<ParkingClassify> find = jdbcSession.findPage(ParkingClassify.class);
		find.like(jsonObject,"name");

		find.eq(jsonObject, "communityNo")
    			.like(jsonObject, "communityName")
				.eq("deleted", false)
				.order("createTime", "desc")
				.page(jsonObject);

		try {
			PermissionNameDto dto = getParkingClassifyPermissionNameDto();

			houseService.setDataSql(find, dto, jsonObject, null);

			Page<ParkingClassify> page = find.exe(false);

			return page;
		}catch (Exception e){
			logger.debug("page=========", e);
		}
		return new Page<>();
    }

	@HasPermission("basic:parking:classify:view")
	@ReqMapping("/getParkingClassifyCascaders")
	public Object getParkingClassifyCascaders(JSONObject jsonObject) {
		FindArray<Community> find = jdbcSession.findArray(Community.class)
				.eq("deleted", false);

		PermissionNameDto dto = houseService.getCommunityPermissionNameDto();

		DataPermissionQuery.setAllDataSql(find, dto, null);

		List<Community> communitys = find.exe(false);

		Map<String, List<JSONObject>> buildMap = getParkingClassifyMap();

		List<JSONObject> array = new ArrayList<>();
		communitys.forEach(item->{
			array.add(community2JSONObject(item, buildMap));
		});

    	return array;
	}

	public Map<String, List<JSONObject>> getParkingClassifyMap() {
		FindArray<ParkingClassify> find = jdbcSession.findArray(ParkingClassify.class)
				.eq("deleted", false);

		PermissionNameDto dto = getParkingClassifyPermissionNameDto();

		DataPermissionQuery.setAllDataSql(find, dto, null);

		List<ParkingClassify> list = find.exe(false);

		Map<String, List<JSONObject>> result = new HashMap<>();
		list.forEach(item->{
			List<JSONObject> builds = result.get(item.getCommunityNo());
			if(Objects.isNull(builds)){
				builds = new ArrayList<>();
			}
			builds.add(build2JSONObject(item));
			result.put(item.getCommunityNo(), builds);
		});

		return result;
	}

	private JSONObject build2JSONObject(ParkingClassify build) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("value", build.getId());
		jsonObject.put("label",build.getName());
		return jsonObject;
	}

	private JSONObject community2JSONObject(Community community, Map<String, List<JSONObject>> buildMap) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("value", community.getId());
		jsonObject.put("label", community.getName());
		jsonObject.put("children", buildMap.get(community.getId()));
		return jsonObject;
	}

    @HasPermission("basic:parking:classify:view")
    @ReqMapping("/get")
    public Object get(ParkingClassify item) {
    	return item;
    }

	@ReqMapping("/setStatus")
	public Object setStatus(ParkingClassify entity) {
		entity.setEnable(!entity.isEnable());
		jdbcSession.updateById(entity);

		return Result.success();
	}
    
    @Bean(newInstance=true, copy=true)
    @HasPermission("basic:parking:classify:edit")
    @ReqMapping("/save")
    public Object save(Token token , ParkingClassify parkingClassify) throws Exception {
		FindOne<ParkingClassify> find = jdbcSession.findOne(ParkingClassify.class)
				.eq("deleted", false)
				.eq("communityNo", parkingClassify.getCommunityNo())
				.eq("name", parkingClassify.getName());
		ParkingClassify item = find.exe(false);

		if(Objects.nonNull(item)){
			return Result.error(0, "当前小区下已有相同的车位分类信息，请修改后重试");
		}

		Community com = Pool.get(Community.class, parkingClassify.getCommunityNo());
		parkingClassify.setDepartmentNo(com.getParent_id());
		parkingClassify.setDepartmentNos(com.getParent_ids());
		parkingClassify.setCreate_by(token.getUsername());
		parkingClassify.setCreateUserId(token.getUuid());
		parkingClassify.setCreateDepartment(token.getDepartments());
		parkingClassify.setCreateChildDepartment(getChildDepartments(token.getDepartments()));
    	
    	jdbcSession.insert(parkingClassify);
    	return Result.success(parkingClassify);
    }

    @Bean(copy=true)
    @HasPermission("basic:parking:classify:edit")
    @ReqMapping("/update")
    public Object update(ParkingClassify parkingClassify) throws Exception {

		FindOne<ParkingClassify> find = jdbcSession.findOne(ParkingClassify.class)
				.eq("deleted", false)
				.eq("communityNo", parkingClassify.getCommunityNo())
				.eq("name", parkingClassify.getName())
				.noEq("id", parkingClassify.getId());
		ParkingClassify item = find.exe(false);

		if(Objects.nonNull(item)){
			return Result.error(0, "当前小区下已有相同的车位分类信息，请修改后重试");
		}

		Community com = Pool.get(Community.class, parkingClassify.getCommunityNo());
		parkingClassify.setDepartmentNo(com.getParent_id());
		parkingClassify.setDepartmentNos(com.getParent_ids());
    	
    	jdbcSession.updateById(parkingClassify);
    	return Result.success();
    }

    @HasPermission("basic:parking:classify:edit")
    @ReqMapping("/delete")
	public Object delete(ParkingClassify item) {

		List<Parking> parkings = jdbcSession.findArray(Parking.class)
				.eq("communityNo", item.getCommunityNo())
				.eq("classNo", item.getId())
				.eq("deleted", false)
				.exe();

		if(Objects.nonEmpty(parkings)){
			return Result.error(0, "需先删除该车位分类下的车位，再删除该车位分类！");
		}


		item.setDeleted(true);
		jdbcSession.updateById(item);
		
		return Result.success();
	}

	@HasPermission("basic:community:edit")
	@ReqMapping("/deleteAll")
	public Object deleteAll(JSONObject jsonObject){
		List<ParkingClassify> list = jdbcSession.findArray(ParkingClassify.class)
				.in("id", jsonObject.getJSONArray("ids"))
				.eq("deleted", false)
				.exe(false);

		List<String> errMsgs = new ArrayList<>();
		list.forEach(item ->{
			List<Parking> parkings = jdbcSession.findArray(Parking.class)
					.eq("communityNo", item.getCommunityNo())
					.eq("classNo", item.getId())
					.eq("deleted", false)
					.exe(false);

			if(Objects.nonEmpty(parkings)){
				errMsgs.add("[" + item.getName() + "]需先删除该车位分类下的车位，再删除该车位分类！");
			}else{
				item.setDeleted(true);
			}
		});

		if (!errMsgs.isEmpty()) {
			return Result.error(0, "删除失败", errMsgs);
		}

		jdbcSession.updateById(list);

		return Result.success();
	}

	@ReqMapping("/checkFile")
	public Object checkFile(JSONObject jsonObject) throws Exception {
		InputStream is = fileUrlConfig.download(jsonObject.getString("fileId"));
		Workbook wb = WorkbookFactory.create(is);
		Sheet sheet = wb.getSheetAt(0);

		// 3行表头 开始读
		Row firstRow = sheet.getRow(sheet.getFirstRowNum() + 2);
		List<String> errMsgs = new ArrayList<>();

		for (int i = firstRow.getFirstCellNum(); i < firstRow.getLastCellNum(); i++) {
			firstRow.getCell(i).setCellType(CellType.STRING);
			String s = firstRow.getCell(i).getStringCellValue();
			if (i < EXCEL_IMPORT_HEADER.length) {
				if (!EXCEL_IMPORT_HEADER[i].equals(s)) {
					errMsgs.add("请确认【" + EXCEL_IMPORT_HEADER[i] + "】为第" + (i + 1) + "列");
				}
			}
		}

		JSONObject errorJson = new JSONObject();
		// 表头校验结果
		if (!errMsgs.isEmpty()) {
			errorJson.put("normalCount", 0);
			errorJson.put("errCount", 0);
			errorJson.put("successCount", 0);
			errorJson.put("errMsgs", errMsgs);
			return Result.error(0, "数据解析异常", errorJson);
		}

		Map<Integer,Integer> errCount = new HashMap<>();
		Integer size = 0;

		// 第4行开始遍历获取数据
		for (int rIndex = sheet.getFirstRowNum() + 3; rIndex <= sheet.getLastRowNum(); rIndex++) {
			Row row = sheet.getRow(rIndex);

			if(Objects.isNull(row)){
				continue;
			}

			List<String> cellValues = new ArrayList<>();
			for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
				Cell cell = row.getCell(i);
				if (i < EXCEL_IMPORT_HEADER.length && Objects.nonNull(cell)) {
					cell.setCellType(CellType.STRING);
					String value = cell.getStringCellValue();
					if(Objects.nonEmpty(value)){
						cellValues.add(value);
					}
				}
			}
			if(Objects.isEmpty(cellValues)){
				continue;
			}

			// 校验数据 写入json数据
			checkExcelData(row, (rIndex + 1), errMsgs, errCount);

			size++;
		}

		errorJson.put("normalCount", size);
		if(size > 3000){
			errMsgs = new ArrayList<>();
			errMsgs.add("最多支持导入3000条数据");
			errorJson.put("errCount", 0);
			errorJson.put("successCount", 0);
			errorJson.put("errMsgs", errMsgs);
			return Result.error(0, "数据解析异常", errorJson);
		}

		// 数据读取结果
		if (!errMsgs.isEmpty()) {

			int errSum = 0;
			for (int val: errCount.keySet()) {
				errSum++;
			}

			errorJson.put("errMsgs", errMsgs);
			errorJson.put("errCount", errSum);
			errorJson.put("successCount", size - errSum);

			return Result.error(0, "数据解析异常", errorJson);
		}

		errorJson.put("errMsgs", errMsgs);
		errorJson.put("errCount", 0);
		errorJson.put("successCount", size);
		return Result.success("成功", errorJson);
	}

	@ReqMapping("/readFile")
	public Object readFile(Token token, JSONObject jsonObject) throws Exception {
		InputStream is = fileUrlConfig.download(jsonObject.getString("fileId"));
		Workbook wb = WorkbookFactory.create(is);
		Sheet sheet = wb.getSheetAt(0);

		List<JSONObject> jsons = new ArrayList<>();

		// 第4行开始遍历获取数据
		for (int rIndex = sheet.getFirstRowNum() + 3; rIndex <= sheet.getLastRowNum(); rIndex++) {
			Row row = sheet.getRow(rIndex);

			if(Objects.isNull(row)){
				continue;
			}

			List<String> cellValues = new ArrayList<>();
			for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) {
				Cell cell = row.getCell(i);
				if (i < EXCEL_IMPORT_HEADER.length && Objects.nonNull(cell)) {
					cell.setCellType(CellType.STRING);
					String value = cell.getStringCellValue();
					if(Objects.nonEmpty(value)){
						cellValues.add(value);
					}
				}
			}
			if(Objects.isEmpty(cellValues)){
				continue;
			}

			JSONObject json = new JSONObject();
			// 校验数据 写入json数据
			checkExcelData(row, json);

			jsons.add(json);
		}

		List<String> childDepartments = getChildDepartments(token.getDepartments());

		jsons.forEach(json->{
			ParkingClassify parkingClassify = jdbcSession.findOne(ParkingClassify.class)
					.eq("deleted", false)
					.eq(json, "communityNo","name")
					.exe();
			if(Objects.nonNull(parkingClassify)){
				setExcelData(parkingClassify, json);
				jdbcSession.updateById(parkingClassify);
			}else{
				parkingClassify = Pool.newInstance(ParkingClassify.class);
				setExcelData(parkingClassify, json);

				parkingClassify.setCreate_by(token.getUsername());
				parkingClassify.setCreateUserId(token.getUuid());
				parkingClassify.setCreateDepartment(token.getDepartments());
				parkingClassify.setCreateChildDepartment(childDepartments);

				jdbcSession.insert(parkingClassify);
			}
		});

		return Result.success();
	}

	private void setExcelData(ParkingClassify item, JSONObject json){
		item.setCommunityNo(json.getString("communityNo"));
		item.setCommunityName(json.getString("communityName"));
		item.setName(json.getString("name"));

		Community com = Pool.get(Community.class, item.getCommunityNo());
		item.setDepartmentNo(com.getParent_id());
		item.setDepartmentNos(com.getParent_ids());
	}

	private void checkExcelData(Row row, int index, List<String> errMsgs, Map<Integer,Integer> errorCount) throws Exception {
		Community community = null;
		String communityName = ExcelUtil.getCellValue(row.getCell(0));
		if (Objects.isEmpty(communityName)) {
			errorCount.put(index, 1);
			errMsgs.add("第" + index + "行：【项目/小区】不能为空");
		}else{
			community = jdbcSession.findOne(Community.class)
					.eq("deleted", false)
					.eq("name", communityName)
					.exe();
			if(Objects.isNull(community)){
				errorCount.put(index, 1);
				errMsgs.add("第"+ index +"行,未获取到当前【小区信息】,请检查");
			}
		}

		String parkingClassifyName = ExcelUtil.getCellValue(row.getCell(1));
		if(Objects.isEmpty(parkingClassifyName)){
			errorCount.put(index, 1);
			errMsgs.add("第" + index + "行：【车位分类】不能为空");
		}
	}

	private void checkExcelData(Row row, JSONObject json) throws Exception {
		Community community = null;
		String communityName = ExcelUtil.getCellValue(row.getCell(0));
		if (Objects.nonEmpty(communityName)) {
			community = jdbcSession.findOne(Community.class)
					.eq("deleted", false)
					.eq("name", communityName)
					.exe();
			if(Objects.nonNull(community)){
				json.put("communityName", communityName);
				json.put("communityNo", community.getId());
			}
		}

		String parkingClassifyName = ExcelUtil.getCellValue(row.getCell(1));
		if(Objects.nonEmpty(parkingClassifyName)){
			json.put("name", parkingClassifyName);
		}
	}

	@HasPermission("basic:parking:classify:view")
	@ReqMapping("/export")
	public Object export(JSONObject jsonObject) throws Exception {

		File tmpFile = null;
		Boolean isModel = jsonObject.getBoolean("isModel");

		if(isModel){
			Workbook wb = generateWorkBook();

			tmpFile = ExcelUtil.writeXlsFile(wb, "车位分类导入模板", ".xlsx");
		}else {
			jsonObject.put("pageNo",1);
			jsonObject.put("pageSize",Short.MAX_VALUE);
			FindPage<ParkingClassify> findPage = jdbcSession.findPage(ParkingClassify.class);
			findPage.like(jsonObject,"name");

			findPage.eq(jsonObject, "communityNo")
					.like(jsonObject, "communityName")
					.eq("deleted", false)
					.page(jsonObject);

			PermissionNameDto dto = getParkingClassifyPermissionNameDto();

			houseService.setDataSql(findPage, dto, jsonObject, null);

			Page<ParkingClassify> page = findPage.exe(false);

			Workbook wb = generateWorkBook(page.getList());

			tmpFile = ExcelUtil.writeXlsFile(wb, "车位分类信息", ".xlsx");
		}

		return Result.download(tmpFile);
	}

	public XSSFWorkbook generateWorkBook() throws Exception {
		// 生成模板文件
		XSSFWorkbook wb = new XSSFWorkbook();

		// 设置头信息
		Sheet sheet = setSheetCellStyle(wb);

		int cellNum = 0;

		Row row = sheet.createRow(3);
		row.createCell(cellNum++).setCellValue("七星商业广场");
		row.createCell(cellNum++).setCellValue("固定车位");

		for (int i = 0; i < cellNum; i++) {
			this.autoSizeColumn(sheet, i);
		}

		return wb;
	}

	public XSSFWorkbook generateWorkBook(List<ParkingClassify> list) throws Exception {
		// 生成模板文件
		XSSFWorkbook wb = new XSSFWorkbook();

		// 设置头信息
		Sheet sheet = setSheetCellStyle(wb);

		int cellNum = 0;
		for (int i = 0; i < list.size(); i++) {
			cellNum = 0;
			ParkingClassify build = list.get(i);
			Row row = sheet.createRow(i + 3);
			row.createCell(cellNum++).setCellValue(build.getCommunityName());
			row.createCell(cellNum++).setCellValue(build.getName() );
		}

		for (int i = 0; i < cellNum; i++) {
			this.autoSizeColumn(sheet, i);
		}
		return wb;
	}

	/**
	 * 自动列宽 为了初始展开时须知内容展示信息比较全故设置最小宽度
	 */
	public void autoSizeColumn(Sheet sheet, int i) {
		if (sheet == null) {
			return;
		}

		// 设置列宽
		int mixWidth = new Double((20+0.71)*256).intValue();

		// 调整每一列宽度
		sheet.autoSizeColumn(i);
		// 解决自动设置列宽中文失效的问题
		int width = sheet.getColumnWidth(i) * 17 / 10;

		if(width < mixWidth){
			width = mixWidth;
		}
		// 避免宽度过长导致抛异常
		if (width > 255 * 256) {
			width = 255 * 10;
		}
		sheet.setColumnWidth(i, width);
	}

	private Sheet setSheetCellStyle(XSSFWorkbook wb){
		//设置字体颜色+文字水平居中
		CellStyle fontColorCellStyle = wb.createCellStyle();
		XSSFFont font = wb.createFont();
		XSSFColor color = new XSSFColor(new java.awt.Color(255,0,0));
		font.setColor(color);
		fontColorCellStyle.setAlignment(HorizontalAlignment.CENTER);
		fontColorCellStyle.setFont(font);

		// 允许文字换行
		XSSFFont fontStyle = wb.createFont(); // 字体样式
//		fontStyle.setBold(true);// 加粗
		fontStyle.setFontName("宋体");
		fontStyle.setFontHeightInPoints((short) 16); // 大小
		CellStyle noticeCellStyle = wb.createCellStyle();
		noticeCellStyle.setWrapText(true);
		noticeCellStyle.setFont(fontStyle);

		// 文字水平居中
		CellStyle fontCellStyle = wb.createCellStyle();
		fontCellStyle.setAlignment(HorizontalAlignment.CENTER);

		Sheet sheet = wb.createSheet();

		// 设置第1行 合并17格
		sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 1));
		// 设置第2行 合并格
		sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 1));

		//第1行 须知内容
		Row noticeRow = sheet.createRow(0);
		Cell noticeRowCell = noticeRow.createCell(0);
		noticeRowCell.setCellStyle(noticeCellStyle);
		StringBuffer notice = new StringBuffer();
		notice.append("填写须知：").append("\n")
				.append(" <1>").append("\n");

		noticeRowCell.setCellValue(notice.toString());
		//自动设置行高
		int colLength = noticeRowCell.getStringCellValue().getBytes().length * 20;
		noticeRow.setHeight((short) (colLength));

		//第2行 员工信息：
		Row firstRow = sheet.createRow(1);
		Cell firstRowCell = firstRow.createCell(0);
		firstRowCell.setCellValue("车位分类信息");
		firstRowCell.setCellStyle(fontCellStyle);

		//第3行 表头
		Row headerRow = sheet.createRow(2);
		for (int i = 0; i < EXCEL_IMPORT_HEADER.length; i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellStyle(fontColorCellStyle);
			cell.setCellValue(EXCEL_IMPORT_HEADER[i]);
		}

		return sheet;
	}

	public List<String> getChildDepartments(List<String> departments) throws Exception {
		JSONObject result = doveClient.post("/basic/department/service/getChildDepartments", http->{
			JSONObject body = new JSONObject();
			body.put("pidList", departments);
			http.setBody(body.toString());
		});

		if (result.getIntValue("code") == 200) {
			JSONArray data = result.getJSONArray("data");
			if(Objects.nonEmpty(data)){
				return JSONObject.parseArray(data.toJSONString(), String.class);
			}
		}
		return new ArrayList<>();
	}

	private PermissionNameDto getParkingClassifyPermissionNameDto(){
		PermissionNameDto dto =  new PermissionNameDto();
		// 指定人员
		dto.setManageUserId("employeeNos");
		// 创建人的部门
		dto.setDepartmentNo("createDepartment");
		// 创建人的部门树
		dto.setDepartmentNos("createChildDepartment");
		// 指定部门
		dto.setManageDepartmentNo("departmentNo");

		return dto;
	}
}
